package com.example.springboot3demo.mq.handler;

import com.example.springboot3demo.config.RabbitMQConfig;
import com.example.springboot3demo.mq.dto.MethodInvocationDto;
import com.example.springboot3demo.util.MqProcessingMarker;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 方法调用处理器
 * 接收RabbitMQ中的方法调用消息，并通过反射执行相应的方法
 *
 * @author Your Name
 * @date 2024-01-01
 */
@Slf4j
@Component
public class MethodInvocationHandler {
    
    // 使用专门的工具类来标记MQ消息处理状态

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ConversionService conversionService;
    
//    @Override
//    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//        this.applicationContext = applicationContext;
//        // 初始化ConversionService
//        this.conversionService = new DefaultConversionService();
//    }
    
    /**
     * 监听方法同步队列，处理接收到的方法调用消息
     * 
     * @param methodInvocationDto 方法调用信息
     */
    @RabbitListener(queues = RabbitMQConfig.METHOD_SYNC_QUEUE)
    public void handleMethodInvocation(MethodInvocationDto methodInvocationDto) {
        try {
            log.info("接收到方法调用消息: {}", methodInvocationDto);
            
            // 设置标记，表示当前线程正在处理MQ消息
            MqProcessingMarker.markAsProcessing();
            
            // 通过反射执行方法
            invokeMethod(methodInvocationDto);
        } catch (Exception e) {
            log.error("处理方法调用消息失败: {}", methodInvocationDto, e);
        } finally {
            // 清除标记
            MqProcessingMarker.clearProcessing();
        }
    }
    
    /**
     * 通过反射执行方法
     * 
     * @param methodInvocationDto 方法调用信息
     * @throws Exception 反射执行异常
     */
    private void invokeMethod(MethodInvocationDto methodInvocationDto) throws Exception {
        // 获取类
        Class<?> clazz = Class.forName(methodInvocationDto.getClassName());
        
        // 获取参数类型
        String[] parameterTypeNames = methodInvocationDto.getParameterTypes();
        Class<?>[] parameterTypes = new Class[parameterTypeNames.length];
        for (int i = 0; i < parameterTypeNames.length; i++) {
            parameterTypes[i] = getClassForName(parameterTypeNames[i]);
        }
        
        // 获取方法
        Method method = clazz.getMethod(methodInvocationDto.getMethodName(), parameterTypes);
        
        // 从Spring容器中获取bean实例
        Object instance = applicationContext.getBean(clazz);
        
        // 获取参数值并进行类型转换
        Object[] parameterValues = methodInvocationDto.getParameterValues();
        Object[] convertedParameters = new Object[parameterValues.length];
        for (int i = 0; i < parameterValues.length; i++) {
            convertedParameters[i] = convertParameter(parameterValues[i], parameterTypes[i]);
        }
        
        // 执行方法
        method.invoke(instance, convertedParameters);
        
        log.info("方法执行成功: {}.{}", methodInvocationDto.getClassName(), methodInvocationDto.getMethodName());
    }
    
    /**
     * 根据类名获取Class对象
     *
     * @param className 类名
     * @return Class对象
     * @throws ClassNotFoundException 类未找到异常
     */
    private Class<?> getClassForName(String className) throws ClassNotFoundException {
        // 处理基本数据类型
        switch (className) {
            case "boolean":
                return boolean.class;
            case "byte":
                return byte.class;
            case "char":
                return char.class;
            case "short":
                return short.class;
            case "int":
                return int.class;
            case "long":
                return long.class;
            case "float":
                return float.class;
            case "double":
                return double.class;
            case "void":
                return void.class;
            default:
                return Class.forName(className);
        }
    }
    
    /**
     * 将参数值转换为指定类型
     *
     * @param value 参数值
     * @param targetType 目标类型
     * @return 转换后的参数值
     */
    public Object convertParameter(Object value, Class<?> targetType) {
        if (value == null || targetType.isInstance(value)) {
            return value;
        }

        try {
            // 特殊处理：如果值是Map且目标类型是自定义对象，则使用BeanWrapper进行转换
            if (value instanceof Map && isCustomObject(targetType)) {
                // 创建目标类型的实例
                Object targetObject = targetType.getDeclaredConstructor().newInstance();

                // 使用BeanWrapper进行属性设置
                BeanWrapper beanWrapper = new BeanWrapperImpl(targetObject);
                beanWrapper.setConversionService(conversionService);

                // 将Map转换为MutablePropertyValues并设置到BeanWrapper
                MutablePropertyValues propertyValues = new MutablePropertyValues((java.util.Map<?, ?>) value);
                beanWrapper.setPropertyValues(propertyValues);

                return targetObject;
            }

            // 特殊处理：如果值是JSON字符串且目标类型是自定义对象，则使用ObjectMapper直接转换
            if (value instanceof String && isCustomObject(targetType)) {
                return new ObjectMapper().readValue((String) value, targetType);
            }

            // 使用Spring的ConversionService进行类型转换
            if (conversionService.canConvert(value.getClass(), targetType)) {
                return conversionService.convert(value, targetType);
            }
        } catch (Exception e) {
            log.warn("使用ConversionService转换失败: {} -> {}", value.getClass().getSimpleName(), targetType.getSimpleName(), e);
        }

        // 如果ConversionService无法转换，返回原值
        // 可能会导致后续的类型不匹配错误，但这与原有逻辑一致
        return value;
    }
    
    /**
     * 判断是否为自定义对象类型
     * 
     * @param clazz 类型
     * @return 是否为自定义对象
     */
    private boolean isCustomObject(Class<?> clazz) {
        // 排除基本数据类型、包装类型和String等常见类型
        return !clazz.isPrimitive() && 
               !clazz.getName().startsWith("java.lang") && 
               !clazz.getName().startsWith("java.util") &&
               !clazz.getName().startsWith("java.time") &&
               !clazz.equals(String.class) &&
               !clazz.equals(Boolean.class) &&
               !clazz.equals(Character.class) &&
               !clazz.equals(Byte.class) &&
               !clazz.equals(Short.class) &&
               !clazz.equals(Integer.class) &&
               !clazz.equals(Long.class) &&
               !clazz.equals(Float.class) &&
               !clazz.equals(Double.class);
    }

}